/* 
 * This code is part of the smartlink project, see
 * 
 * 		http://code.google.com/p/smartlink/.
 * 
 * Copyright (C) 2008 Oliver Noelle
 * 
 * SmartLink is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * SmartLink is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with SmartLink.  If not, see <http://www.gnu.org/licenses/>.
 **/
package org.smartlink;

import java.util.HashMap;

import org.smartlink.provider.SmartLink;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

/**
 * Provides access to a database of links. Each link has a key, the target , a
 * creation date and a modified data.
 * 
 */
public class SmartLinkProvider extends ContentProvider {

	private static final String PROVIDER = "org.smartlink.provider.SmartLink";

	private SQLiteDatabase mDB;

	private static final String TAG = "SmartLinkProvider";
	private static final String DATABASE_NAME = "smart_link.db";
	/**
	 * v2: before introducing description, v3: introduced description
	 */
	private static final int DATABASE_VERSION = 3;
	private static final String SMARTLINK_TABLENAME = "smartlink";

	private static HashMap<String, String> LINK_LIST_PROJECTION_MAP;

	private static final int LINKS = 1;
	private static final int LINK_ID = 2;
	private static final int LINK_LOOKUP = 3;

	private static final UriMatcher URL_MATCHER;

	private static class DatabaseHelper extends SQLiteOpenHelper {

		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL("CREATE TABLE " + SMARTLINK_TABLENAME + " (_id INTEGER PRIMARY KEY," + "key TEXT,"
					+ "target TEXT," + "description TEXT," + "created INTEGER," + "modified INTEGER" + ");");
		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion
					+ ", which will destroy all old data");
			db.execSQL("DROP TABLE IF EXISTS " + SMARTLINK_TABLENAME);
			onCreate(db);
		}
	}

	@Override
	public boolean onCreate() {
		DatabaseHelper dbHelper = new DatabaseHelper();
		mDB = dbHelper.openDatabase(getContext(), DATABASE_NAME, null, DATABASE_VERSION);
		return (mDB == null) ? false : true;
	}

	@Override
	public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sort) {
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

		switch (URL_MATCHER.match(url)) {
		case LINKS:
			qb.setTables(SMARTLINK_TABLENAME);
			qb.setProjectionMap(LINK_LIST_PROJECTION_MAP);
			break;

		case LINK_ID:
			qb.setTables(SMARTLINK_TABLENAME);
			qb.appendWhere("_id=" + url.getPathSegments().get(1));
			break;

		case LINK_LOOKUP:
			qb.setTables(SMARTLINK_TABLENAME);
			qb.setProjectionMap(LINK_LIST_PROJECTION_MAP);
			break;

		default:
			throw new IllegalArgumentException("xxxUnknown URL " + url);
		}

		// If no sort order is specified use the default
		String orderBy;
		if (TextUtils.isEmpty(sort)) {
			orderBy = SmartLink.Links.DEFAULT_SORT_ORDER;
		} else {
			orderBy = sort;
		}

		Cursor c = qb.query(mDB, projection, selection, selectionArgs, null, null, orderBy);
		c.setNotificationUri(getContext().getContentResolver(), url);
		return c;
	}

	@Override
	public String getType(Uri url) {
		switch (URL_MATCHER.match(url)) {
		case LINKS:
			return "vnd.android.cursor.dir/vnd.google.link";

		case LINK_ID:
			return "vnd.android.cursor.item/vnd.google.link";

		case LINK_LOOKUP:
			return "vnd.android.cursor.item/vnd.google.link";

		default:
			throw new IllegalArgumentException("xyyzUnknown URL " + url);
		}
	}

	@Override
	public Uri insert(Uri url, ContentValues initialValues) {
		long rowID;
		ContentValues values;
		if (initialValues != null) {
			values = new ContentValues(initialValues);
		} else {
			values = new ContentValues();
		}

		if (URL_MATCHER.match(url) != LINKS) {
			throw new IllegalArgumentException("yUnknown URL " + url);
		}

		Long now = Long.valueOf(System.currentTimeMillis());
		// Resources r = Resources.getSystem();

		// Make sure that the fields are all set
		if (values.containsKey(SmartLink.Links.CREATED_DATE) == false) {
			values.put(SmartLink.Links.CREATED_DATE, now);
		}

		if (values.containsKey(SmartLink.Links.MODIFIED_DATE) == false) {
			values.put(SmartLink.Links.MODIFIED_DATE, now);
		}

		if (values.containsKey(SmartLink.Links.KEY) == false) {
			values.put(SmartLink.Links.KEY, "");
		}

		if (values.containsKey(SmartLink.Links.TARGET) == false) {
			values.put(SmartLink.Links.TARGET, "");
		}

		if (values.containsKey(SmartLink.Links.DESCRIPTION) == false) {
			values.put(SmartLink.Links.DESCRIPTION, "");
		}

		rowID = mDB.insert(SMARTLINK_TABLENAME, "link", values);
		if (rowID > 0) {
			Uri uri = ContentUris.withAppendedId(SmartLink.Links.CONTENT_URI, rowID);
			getContext().getContentResolver().notifyChange(uri, null);
			return uri;
		}

		throw new SQLException("Failed to insert row into " + url);
	}

	@Override
	public int delete(Uri url, String where, String[] whereArgs) {
		int count;
		// long rowId = 0;
		switch (URL_MATCHER.match(url)) {
		case LINKS:
			count = mDB.delete(SMARTLINK_TABLENAME, where, whereArgs);
			break;

		case LINK_ID:
			String segment = url.getPathSegments().get(1);
			// rowId = Long.parseLong(segment);
			count = mDB.delete(SMARTLINK_TABLENAME, "_id=" + segment
					+ (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
			break;

		default:
			throw new IllegalArgumentException("zUnknown URL " + url);
		}

		getContext().getContentResolver().notifyChange(url, null);
		return count;
	}

	@Override
	public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
		int count;
		switch (URL_MATCHER.match(url)) {
		case LINKS:
			count = mDB.update(SMARTLINK_TABLENAME, values, where, whereArgs);
			break;

		case LINK_ID:
			String segment = url.getPathSegments().get(1);
			count = mDB.update(SMARTLINK_TABLENAME, values, "_id=" + segment
					+ (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
			break;

		default:
			throw new IllegalArgumentException("aUnknown URL " + url);
		}

		getContext().getContentResolver().notifyChange(url, null);
		return count;
	}

	static {
		URL_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
		URL_MATCHER.addURI(PROVIDER, "links", LINKS);
		URL_MATCHER.addURI(PROVIDER, "links" + "/#", LINK_ID);
		URL_MATCHER.addURI(PROVIDER, "lookup" + "/*", LINK_LOOKUP);

		LINK_LIST_PROJECTION_MAP = new HashMap<String, String>();
		LINK_LIST_PROJECTION_MAP.put(SmartLink.Links._ID, "_id");
		LINK_LIST_PROJECTION_MAP.put(SmartLink.Links.KEY, "key");
		LINK_LIST_PROJECTION_MAP.put(SmartLink.Links.TARGET, "target");
		LINK_LIST_PROJECTION_MAP.put(SmartLink.Links.DESCRIPTION, "description");
		LINK_LIST_PROJECTION_MAP.put(SmartLink.Links.CREATED_DATE, "created");
		LINK_LIST_PROJECTION_MAP.put(SmartLink.Links.MODIFIED_DATE, "modified");
	}
}
